#include <windows.h>
#include <commctrl.h>
#include <tchar.h>
#include <stdio.h>
#include "dllmain.h"
#include "listview.h"
#include "tracelog.h"
#include "trayicon.h"
#include "resource.h"
#include "w_detail.h"
#include "log.h"
#include "ini.h"

extern HWND hwndMain;
extern bool	isWndTopmost;
extern long	delayLog;


long pOldLVWndProc=0;
_TCHAR *lvclassname=_T("tracelog.listview");
_TCHAR colName[LV_COL_COUNT][10] = {_T("Time"),_T("Mask"),_T("Object"),_T("Message")};

BOOL popupContextMenu(HWND hWnd, WPARAM wParam, LPARAM lParam) {
	HMENU hMenuLoad, hMenu;
	int x,y;
	hMenuLoad = LoadMenu(getInstance(), MAKEINTRESOURCE(IDR_MENU1));
	hMenu = GetSubMenu(hMenuLoad, 0); 
	if(lParam==-1){
		RECT r;
		GetWindowRect(hWnd,&r);
		x=r.left;
		y=r.top;
	}else{
		x=LOWORD(lParam);
		y=HIWORD(lParam);
	}
/*	if ( ini_getShowDebugSql() ) {
		MENUITEMINFO mii_dbg;
		mii_dbg.cbSize=sizeof(MENUITEMINFO);
		mii_dbg.fMask=MIIM_STATE;
		mii_dbg.fState=MFS_CHECKED;
		
		SetMenuItemInfo(hMenu,ID_SHOW_DEBUGSQL,FALSE,&mii_dbg);
	}
*/	MSG msg;
	MENUITEMINFO mii;
	mii.cbSize=sizeof(MENUITEMINFO);
	mii.fMask = MIIM_STATE;
	mii.fState = isWndTopmost ? MFS_CHECKED : MFS_UNCHECKED;
	SetMenuItemInfo(hMenu,ID_LOG_ALWAYSONTOP,FALSE,&mii);

	mii.fMask = MIIM_STATE;
	mii.fState = delayLog ? MFS_CHECKED : MFS_UNCHECKED;
	SetMenuItemInfo(hMenu,ID_LOG_DELAY,FALSE,&mii);


	SetForegroundWindow(hWnd);
	PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE);
	TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_LEFTBUTTON, x, y, 0, GetParent(hWnd),  NULL);
	DestroyMenu(hMenuLoad);
	return TRUE; 
} 


BOOL WINAPI InitListViewImageLists(HWND hwndLV) { 
	HIMAGELIST himl;
 
	himl = ImageList_Create(16, 16, ILC_COLORDDB | ILC_MASK, 1, 0);
	if ( himl ) {
		HICON hIcon;
		hIcon = LoadIcon(NULL, IDI_ERROR);
		ImageList_AddIcon(himl, hIcon);

		hIcon = LoadIcon(NULL, IDI_WARNING);
		ImageList_AddIcon(himl, hIcon);

		hIcon = LoadIcon(NULL, IDI_INFORMATION);
		ImageList_AddIcon(himl, hIcon);

		ListView_SetImageList(hwndLV, himl, LVSIL_SMALL);
		ListView_SetImageList(hwndLV, himl, LVSIL_NORMAL);
	} else {
		log(_T("ERR: InitListViewImageLists:himl NULL.\n"));
	}
	return TRUE; 
} 

BOOL WINAPI InitListViewColumns(HWND hwndLV) { 
	int iAlign[LV_COL_COUNT] = {LVCFMT_LEFT, LVCFMT_RIGHT, LVCFMT_LEFT, LVCFMT_LEFT};
	int defWidth[LV_COL_COUNT] = {90,90, 150, 320};


	LVCOLUMN lvc; 
	int i; 
	_TCHAR key[20];
 
	// Initialize the LVCOLUMN structure. 
	lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; 
 
	// Add the columns. 
	for (i = 0; i < LV_COL_COUNT; i++) { 
		lvc.fmt = iAlign[i]; 
		lvc.iSubItem = i; 
		lvc.pszText = colName[i];
		wsprintf(key, _T("col%i"), i);
		lvc.cx = ini_getint(lvclassname,key,defWidth[i]); 
		if ( ListView_InsertColumn(hwndLV, i, &lvc) == -1 ) return FALSE; 
	} 
	return TRUE; 
} 

long CALLBACK lvWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
   switch (message) {
	  case WM_LBUTTONDBLCLK:
		 int idx;
		 //if ( g_hwndMemo != NULL ) break;
		 LVHITTESTINFO lvhi;
		 lvhi.pt.x = LOWORD(lParam);
		 lvhi.pt.y = HIWORD(lParam);
		 lvhi.flags = LVHT_TOLEFT;
		 lvhi.iItem = 0;
		 lvhi.iSubItem = 0;
		 if ( (idx = ListView_HitTest(hWnd, &lvhi)) == -1 ) break;
		 	showDetailWindow();
		 break;
	  case WM_CONTEXTMENU:
		 popupContextMenu( hWnd , wParam, lParam);
		 break;
   }
   return CallWindowProc( (WNDPROC)pOldLVWndProc, hWnd, message, wParam, lParam); 
}


HWND WINAPI createListView(HWND hwndParent) { 
	HWND hwnd;

	// Force the common controls DLL to be loaded. 
	InitCommonControls(); 
	RECT rc;
	GetClientRect(hwndParent, &rc);
	
	// Create the list view window. 
	hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, _T(""), WS_CHILD | WS_TABSTOP | WS_VISIBLE | LVS_REPORT | LVS_ALIGNLEFT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER,
		0, 0, rc.right - rc.left, rc.bottom - rc.top, hwndParent, NULL, getInstance(), NULL); 
	if (hwnd == NULL) {
		log(_T("ERR: createListView:CreateWindow failed.\n"));
		return NULL; 
	}
	if ( !(pOldLVWndProc = GetWindowLong(hwnd, GWL_WNDPROC)) ) {
		log(_T("ERR: createListView:GetWindowLong failed.\n"));
		return NULL; 
	}
	
	if ( !SetWindowLong(hwnd, GWL_WNDPROC, (long)lvWndProc) ) {
		log(_T("ERR: createListView:SetWindowLong failed.\n"));
		return NULL; 
	}
	if (!InitListViewImageLists(hwnd) || !InitListViewColumns(hwnd)) { 
		log(_T("ERR: createListView:InitListViewImageLists or InitListViewColumns failed.\n"));
		return NULL; 
	}
	ListView_SetExtendedListViewStyle(hwnd, LVS_EX_FULLROWSELECT);
	ShowWindow(hwnd, SW_SHOW);

	return hwnd;
} 

BOOL saveColWidth(HWND hwnd){
	int i,w;
	_TCHAR key[20];
	for ( i = 0; i < LV_COL_COUNT; i++) {
		w = ListView_GetColumnWidth(hwnd, i);
		_stprintf(key, _T("col%i"), i);
		ini_setint(lvclassname,key,w);
	}
	return 1;
}

BOOL addListViewItem(HWND hwndLV, int mask, SYSTEMTIME * st, _TCHAR * obj, _TCHAR * msg) {
	_TCHAR ctime[30];
	_TCHAR *cmask;

	cmask=getMaskInfo(mask);

	//Get item count
	int iNum = ListView_GetItemCount(hwndLV);

	LV_ITEM lvi; 
	//ZeroMemory(&lvi, sizeof(lvi));
	lvi.mask = LVIF_IMAGE|LVIF_PARAM; //store the max string length in param
	lvi.iItem = iNum + 1;
	lvi.iSubItem = 0;
	lvi.state = 0;
	switch( cmask[0] ){
		case _T('e'): 
			lvi.iImage = 0;
			break;
		case _T('w'): 
			lvi.iImage = 1;
			break;
		default: 
			lvi.iImage = 2;
			break;
	}
	lvi.lParam=max( _tcslen(ctime), max( _tcslen(cmask), max( _tcslen(obj), _tcslen(msg) ) ) );
 
	// Add the item. 
	if ( ListView_InsertItem(hwndLV, &lvi) == -1 ) {
		log(_T("ERR: addListViewItem:ListView_InsertItem failed.\n"));
		return FALSE;   
	}
	_stprintf(ctime, _T("%02d:%02d:%02d.%03d"), st->wHour, st->wMinute, st->wSecond, st->wMilliseconds);
	log(_T("DBG: addListViewItem: ctime:%s, cmask:%u, obj:%s, msg:%s.\n"), ctime, cmask, obj, msg);
	
	ListView_SetItemText(hwndLV, iNum, 0, ctime); 
	ListView_SetItemText(hwndLV, iNum, 1, cmask+2); 
	ListView_SetItemText(hwndLV, iNum, 2, obj); 
	ListView_SetItemText(hwndLV, iNum, 3, msg);
	ListView_Scroll(hwndLV,0,100000);
	if(!IsWindowVisible(hwndMain)){
		if(lvi.iImage==0)alertTrayIcon(hwndMain,2);
		else alertTrayIcon(hwndMain,1);
	}
	
	log(_T("DBG: addListViewItem: OK.\n"));
	return TRUE; 
} 

void setListViewDetail(HWND hwndLV,int item){
	LV_ITEM lvi;

	resetDetailText();
	if(item>=0){
		//get buffer length;
		lvi.iItem=item;
		lvi.iSubItem=0;
		lvi.mask=LVIF_PARAM;
		SendMessage(hwndLV,LVM_GETITEM,item,(LPARAM)&lvi);
		lvi.cchTextMax=lvi.lParam+2;//+2 just to be sure
		lvi.pszText=new _TCHAR[lvi.cchTextMax];
		for(int i=0;i<LV_COL_COUNT;i++){
			appendDetailText(colName[i]);
			appendDetailText(_T("\t"));
			lvi.mask=LVIF_TEXT;
			lvi.iSubItem=i;
			SendMessage(hwndLV,LVM_GETITEMTEXT,item,(LPARAM)&lvi);
			appendDetailText(lvi.pszText);
			if (i<LV_COL_COUNT-1)appendDetailText(_T("\r\n"));
		}
		delete []lvi.pszText;
		lvi.pszText=NULL;
	}	
}

void fputWS(WCHAR*s,FILE*f){
	if(!s)return;
	fwrite( s, 2, wcslen(s), f );
}

void fputWSC(WCHAR*s,FILE*f){
	if(!s)return;
	for(int i=0;s[i];i++){
		switch(s[i]){
			case '\r':
				break;
			case '\n':
				fwrite( L"<br>", 2, 4, f );
				break;
			case '&':
				fwrite( L"&amp;", 2, 5, f );
				break;
			case '<':
				fwrite( L"&lt;", 2, 4, f );
				break;
			case '>':
				fwrite( L"&gt;", 2, 4, f );
				break;
			case '"':
				fwrite( L"&quot;", 2, 6, f );
				break;
			default:
				fwrite( s+i, 2, 1, f );
				break;
		}
	}
}


void saveListViewAs(HWND hwndLV){
	//get filename
	_TCHAR filename[4096]=_T("tracelog.htm");
	_TCHAR *curdir=NULL;
	int   curdirsize=0;
	
	curdirsize=GetCurrentDirectory(0,NULL);
	curdir=new _TCHAR[curdirsize];
	GetCurrentDirectory(curdirsize,curdir);
	 
	OPENFILENAME of;  
	FillMemory((PVOID)&of, sizeof(OPENFILENAME), 0);
	of.lStructSize = sizeof(OPENFILENAME);
	of.hwndOwner = hwndMain;
	of.lpstrFilter = _T("HTML file (*.htm, *.html)\x00*.htm;*.html\x00");
	of.nFilterIndex = 1;
	of.lpstrFile = filename;
	of.nMaxFile = NUMTCHARS(filename);
	of.lpstrDefExt = _T("htm");
	of.Flags = OFN_SHOWHELP | OFN_OVERWRITEPROMPT;
	if(GetSaveFileName(&of)){
		//write html file
		FILE *stream;
		stream = _tfopen(filename, _T("wb"));
		if ( stream ) {
			int nNum,i;
			nNum = ListView_GetItemCount(hwndLV);
			
			fputWS(_T("<html>\n"),stream);
			fputWS(_T("<head>\n<title>Trace Log</title>\n</head>\n"),stream);
			fputWS(_T("<body bgcolor='#808080'>\n\n"),stream);
			fputWS(_T("<table border='1' cellspacing='0' bgcolor='white'>\n"),stream);
			
			
			//write header
			fputWS(_T("<tr bgcolor='silver'>\n"),stream);
			fputWS(_T("<td>&nbsp;</td>\n"),stream);//for icon
			for(i=0;i<LV_COL_COUNT;i++){
				fputWS(_T("<td>"),stream);
				fputWSC(colName[i],stream);
				fputWS(_T("</td>"),stream);
			}
			fputWS(_T("</tr>\n"),stream);
			//write data
			for ( int item = 0; item < nNum; item++ ) {
				fputWS(_T("<tr>\n"),stream);
				
				LV_ITEM lvi;

				//get buffer length;
				lvi.iItem=item;
				lvi.iSubItem=0;
				lvi.mask=LVIF_PARAM|LVIF_IMAGE;
				SendMessage(hwndLV,LVM_GETITEM,item,(LPARAM)&lvi);
				lvi.cchTextMax=lvi.lParam+2;//+2 just to be sure
				lvi.pszText=new _TCHAR[lvi.cchTextMax];
				switch(lvi.iImage){
					case 0:
						fputWS(_T("<th bgcolor='red'>&nbsp;X&nbsp;</th>\n"),stream);
						break;
					case 1:
						fputWS(_T("<th bgcolor='yellow'>&nbsp;!&nbsp;</th>\n"),stream);
						break;
					default:
						fputWS(_T("<th><font color='blue'>&nbsp;i&nbsp;</font></th>\n"),stream);
						break;
				}
				for(int i=0;i<LV_COL_COUNT;i++){
					lvi.mask=LVIF_TEXT;
					lvi.iSubItem=i;
					SendMessage(hwndLV,LVM_GETITEMTEXT,item,(LPARAM)&lvi);
					fputWS(_T("<td>\n"),stream);
					fputWSC(lvi.pszText,stream);
					fputWS(_T("</td>\n"),stream);
				}
				delete []lvi.pszText;
				lvi.pszText=NULL;
				
				fputWS(_T("</tr>\n"),stream);
			}
			fputWS(_T("</table>\n"),stream);
			fputWS(_T("</body></html>\n"),stream);
			fflush(stream);
			fclose(stream);
		} else {
			log_error(_T("saveLogWindow:fopen"));
		}
	}else{
		log(_T("DBG: saveLogWindow:GetSaveFileName failed\n"));
	}
	SetCurrentDirectory(curdir);
	delete []curdir;
}

